package api.service;

import api.model.ApiColumn;
import api.model.ApiConvertData;
import api.model.ApiConvertDataColumn;
import com.alibaba.fastjson.JSONObject;
import m.common.model.util.*;
import m.common.service.Service;
import m.html.element.other.DisplayItem;
import m.system.cache.CacheUtil;
import m.system.db.SqlBuffer;
import m.system.db.TransactionManager;
import m.system.exception.MException;
import m.system.handler.HandlerUtil;
import m.system.util.*;

import java.util.*;
import java.util.stream.Collectors;

public class ApiConvertDataService extends Service {
    /**
     * 获取源数据表列 两层
     */
    public List<DisplayItem> getSourceColumn(String oid){
        List<DisplayItem> tList= new ArrayList<>();
        List<ApiColumn> ls=CacheUtil.getList(ApiColumn.class,oid);
        for(ApiColumn col : ls){
            tList.add(DisplayItem.value(col.getName(),col.getName()+" - "+col.getDescription()));
            if(ObjectUtil.notEmptyOid(col.getModelTable())){
                List<ApiColumn> cols=CacheUtil.getList(ApiColumn.class,col.getModelTable().getOid());
                cols.forEach(item->{
                    if(ObjectUtil.notEmptyOid(item.getModelTable())){
                        tList.add(DisplayItem.value(col.getName()+"."+item.getName()+".oid",col.getName()+"."+item.getName()+".oid - "+item.getDescription(),col.getName()));
                    }else{
                        tList.add(DisplayItem.value(col.getName()+"."+item.getName(),col.getName()+"."+item.getName()+" - "+item.getDescription(),col.getName()));
                    }
                });
            }
        }
        return tList;
    }

    /**
     * 获取保存表列 一层
     */
    public List<DisplayItem> getSaveColumn(String oid){
        List<DisplayItem> tList= new ArrayList<>();
        List<ApiColumn> ls=CacheUtil.getList(ApiColumn.class,oid);
        ls.forEach(item->{
            if(ObjectUtil.notEmptyOid(item.getModelTable())){
                tList.add(DisplayItem.value(item.getName()+".oid",item.getName()+".oid - "+item.getDescription()));
            }else{
                tList.add(DisplayItem.value(item.getName(),item.getName()+" - "+item.getDescription()));
            }
        });
        return tList;
    }

    /**
     * 启用时验证
     */
    public void verifyEnable(String oid) throws Exception{
        ApiConvertData model= ModelQueryList.getModel(ApiConvertData.class,oid,"*");
        List<ApiConvertDataColumn> ls=CacheUtil.getList(ApiConvertDataColumn.class,model.getOid());
        if(ls.isEmpty()) throw new MException(this.getClass(),"没有添加列转换关系");
        List<String> sourceLs=getSourceColumn(model.getSourceTable())
                .stream().map(DisplayItem::getValue).collect(Collectors.toList());
        List<String> saveLs=getSaveColumn(model.getSaveTable())
                .stream().map(DisplayItem::getValue).collect(Collectors.toList());
        if(model.getTriggerCondition().equals("T")){
            if(model.getTimerCondition().equals("A")&&!(sourceLs.contains("sysUpdateTime")||sourceLs.contains("sys_update_time")))
                throw new MException(this.getClass(),"源数据表中需要包含sysUpdateTime或者sys_update_time日期字段");
        }
        boolean oidConvert=false;
        for(ApiConvertDataColumn col : ls){
            if(!sourceLs.contains(col.getSourceColumn())) throw new MException(this.getClass(),"源数据表"+col.getSourceColumn()+"列不存在");
            if(!saveLs.contains(col.getSaveColumn())) throw new MException(this.getClass(),"保存表"+col.getSaveColumn()+"列不存在");
            if(col.getSaveColumn().equals("oid")) oidConvert=true;
        }
        if(!oidConvert) throw new MException(this.getClass(),"未设置保存表oid转换关系");
    }
    public String save(ApiConvertData model, List<JSONObject> columnList) throws Exception {
        String msg;
        TransactionManager tm=new TransactionManager();
        try {
            tm.begin(model.getOid());
            ModelCheckUtil.check(model);
            if(StringUtil.isSpace(model.getOid())){
                model.setOid(GenerateID.generatePrimaryKey());
                ModelUpdateUtil.insertModel(model);
                msg="保存成功";
            }else{
                ModelUpdateUtil.updateModel(model, "description","sourceTable","saveTable","triggerCondition","timerCondition","timerLong","lastDate","dataHandler");
                msg="修改成功";
            }
            for(JSONObject json : columnList){
                if(json.getIntValue("deleteFlag")==1){//tableForm存在oid删除时添加的deleteFlag标识，1代表删除
                    ModelUpdateUtil.deleteModel(json.toJavaObject(ApiConvertDataColumn.class));
                }else{
                    ApiConvertDataColumn column=json.toJavaObject(ApiConvertDataColumn.class);
                    column.setApiConvertData(model);
                    ModelCheckUtil.check(column);
                    if(ObjectUtil.isEmptyOid(column)){
                        column.setOid(GenerateID.generatePrimaryKey());
                        ModelUpdateUtil.insertModel(column);
                    }else{
                        ModelUpdateUtil.updateModel(column);
                    }
                }
            }
            clearCache();
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            throw e;
        }
        return msg;
    }
    public void clearCache(){
        CacheUtil.clear(ApiConvertData.class);
        CacheUtil.clear(ApiConvertDataColumn.class);
        sourceTableNameList=null;
    }
    private static List<String> sourceTableNameList=null;
    /**
     * 是否有源数据表转换
     */
    public static boolean hasSourceTable(String name){
        if(null==sourceTableNameList){
            sourceTableNameList=new ArrayList<>();
            CacheUtil.getList(ApiConvertData.class,"").forEach(item->sourceTableNameList.add(item.getSourceTable()));
        }
        return sourceTableNameList.contains(name);
    }
    private static Object getSourceColumnData(Map<String, Object> sourceData,String sourceCol){
        try {
            return ActionUtil.getInAttribute(sourceData,sourceCol);
        } catch (Exception e) {
            return null;
        }
    }
    private static void setSaveColumnData(Map<String, Object> saveData,String saveCol,Object data){
        String[] colArr=saveCol.split("\\.");
        if(colArr.length>1&&colArr[1].equals("oid")){
            Map<String,Object> map=new HashMap<>();
            map.put("oid",data);
            saveData.put(colArr[0],map);
        }else{
            saveData.put(saveCol,data);
        }
    }

    /**
     * 定时执行更新
     */
    public static void timeExecute(){
        Date t=new Date();
        List<ApiConvertData> ls=CacheUtil.getList(ApiConvertData.class,"");
        for(ApiConvertData cd : ls){
            if(cd.getTriggerCondition().equals("T")
                &&(null==cd.getLastDate()||cd.getLastDate().getTime()+Long.parseLong(cd.getTimerLong())*60*1000<t.getTime()+1000)){//定时执行
                TransactionManager tm=new TransactionManager();
                try {
                    tm.begin();
                    batchUpdateData(cd);
                    cd.setLastDate(t);
                    ModelUpdateUtil.updateModel(cd,"lastDate");
                    tm.commit();
                } catch (Exception e) {
                    tm.rollback();
                    e.printStackTrace();
                    SystemUtil.println("定时执行数据转存错误：",e.getMessage());
                }
            }
        }
    }
    private static void batchUpdateData(ApiConvertData cd) throws Exception {
        QueryCondition cond=null;
        if("A".equals(cd.getTimerCondition())) {//根据sysUpdateTime列
            String sysUpdateDateField = "";
            List<ApiColumn> ls = CacheUtil.getList(ApiColumn.class, cd.getSourceTable());
            for (ApiColumn c : ls) {
                if (c.getName().equals("sysUpdateTime") || c.getName().equals("sys_update_time"))
                    sysUpdateDateField = c.getName();
            }
            Date lastDate = cd.getLastDate();
            if (null == lastDate) lastDate = DateUtil.format("1990-01-01", DateUtil.YYYY_MM_DD);
            cond=QueryCondition.eq(sysUpdateDateField,lastDate);
        }else if("C".equals(cd.getTimerCondition())){//全删后再全量插入
            new SqlBuffer().append("DELETE FROM ").append(cd.getSaveTable()).executeUpdate();
        }
        List<ApiConvertDataColumn> cols=CacheUtil.getList(ApiConvertDataColumn.class,cd.getOid());
        String sourceField= cols.stream().filter(item -> "oid".equals(item.getSaveColumn())).findFirst().map(ApiConvertDataColumn::getSourceColumn).orElse("");
        updateData(cd,cd.getSourceTable(),cd.getSaveTable(), sourceField,
            TableQueryList.getList(cd.getSourceTable(), new String[]{sourceField}, null, cond)
            .stream().map(item -> {
                try {
                    return (String) ActionUtil.getInAttribute(item,sourceField);
                } catch (Exception e) {
                    return null;
                }
            }).toArray(String[]::new)
        );
    }
    private static void updateData(ApiConvertData convertData,String sourceTable,String saveTable,String oidField,String... oids) throws Exception {
        List<ApiConvertDataColumn> cols=CacheUtil.getList(ApiConvertDataColumn.class,convertData.getOid());
        String[] sourceCols= cols.stream().map(ApiConvertDataColumn::getSourceColumn).toArray(String[]::new);
        String[] saveCols= cols.stream().map(ApiConvertDataColumn::getSaveColumn).toArray(String[]::new);
        for(String oid : oids) {
            List<Map<String, Object>> sourceDatas = TableQueryList.getList(sourceTable, sourceCols, new QueryPage(0,1), QueryCondition.eq(oidField, oid));
            if (!sourceDatas.isEmpty()) {
                Map<String, Object> sourceData=sourceDatas.get(0);
                Map<String,Object> saveData=new HashMap<>();
                saveData.put("oid",oid);
                for(ApiConvertDataColumn item : cols){
                    setSaveColumnData(saveData,item.getSaveColumn(),getSourceColumnData(sourceData,item.getSourceColumn()));
                }
                if(!ArrayUtil.isEmpty(convertData.getDataHandler())) {
                    saveData=HandlerUtil.executes(new JSONObject(saveData),null,convertData.getDataHandler()).getInnerMap();
                }
                if(TableQueryList.getList(saveTable, new String[]{"oid"}, new QueryPage(0,1), QueryCondition.eq("oid", oid)).isEmpty()){
                    TableUpdateUtil.insertModel(saveTable,saveData);
                }else{
                    TableUpdateUtil.updateModel(saveTable,saveData,saveCols);
                }
            }
        }
    }
    /**自动执行调用
     * 执行更新数据
     */
    public static void executeUpdateData(String tableOid,String... oids) throws Exception {
        List<ApiConvertData> ls=CacheUtil.getList(ApiConvertData.class,tableOid);
        for(ApiConvertData cd : ls){
            if("A".equals(cd.getTriggerCondition())) {
                updateData(cd, cd.getSourceTable(), cd.getSaveTable(),"oid", oids);
            }
        }
    }

    /**自动执行调用
     * 执行删除数据
     */
    public static void executeDeleteData(String tableOid,String... oids) throws Exception{
        List<ApiConvertData> ls=CacheUtil.getList(ApiConvertData.class,tableOid);
        for(ApiConvertData cd : ls){
            if("A".equals(cd.getTriggerCondition())) {
                for (String oid : oids) {
                    TableUpdateUtil.deleteModel(cd.getSaveTable(), oid);
                }
            }
        }
    }
}
